package com.tcl.mie.launcher.basehttp;

import com.squareup.okhttp.Call;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;

import java.io.IOException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * @Description
 * @author flying
 * @version 1.0
 * @Created on 2016/7/8.
 */
public class HttpTask extends Thread {

    private final static int CONN_TIMEOUT = 30000;
    private final static int READ_TIMEOUT = 30000;
    private final static int BUFF_LEN = 4096;

    private static final int HTTP_ENTITY_INVALID = -1001;
    private static final int HTTP_STATUS_INVALID = -1002;

    OkHttpClient httpClient;
    Request mRequest;
    Call mCall;
    volatile boolean mCancel;

    private static Singleton<OkHttpClient> SINGLE_CLIENT = new Singleton<OkHttpClient>() {
        @Override
        protected OkHttpClient create() {
            OkHttpClient client = new OkHttpClient();
            client.setConnectTimeout(CONN_TIMEOUT, TimeUnit.MILLISECONDS);
            client.setReadTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS);
            supportHttps(client);
            return client;
        }
    };

    public HttpTask(Request request) {
        this.mRequest = request;
        httpClient = SINGLE_CLIENT.get();
    }

    @Override
    public void run() {
        do {
            onHttpPrepare();
            try {
                mCall = httpClient.newCall(mRequest);
                Response response = mCall.execute();
                System.out.println("resonse: " + response);
                if (mCancel) {
                    break;
                }
                if (response == null || response.body() == null) {
                    onHttpError(HttpRequestResult.FAIL_NOT_FOUND, HTTP_ENTITY_INVALID);
                    break;
                }

                int statusCode = response.code();
                ResponseBody entity = response.body();
                if (statusCode != HttpURLConnection.HTTP_OK) {
                    onHttpError(HttpRequestResult.FAIL_NOT_FOUND, HTTP_STATUS_INVALID);
                    break;
                }
                if (entity == null) {
                    onHttpError(HttpRequestResult.FAIL_NOT_FOUND, HTTP_ENTITY_INVALID);
                    break;
                }
                onHttpSuccess(entity);
            } catch (ConnectException e) {
                onHttpError(HttpRequestResult.FAIL_CONNECT_TIMEOUT, HTTP_ENTITY_INVALID);
            } catch (IOException e1) {
                e1.printStackTrace();
                onHttpError(HttpRequestResult.FAIL_IO_ERROR, HTTP_ENTITY_INVALID);
            } catch (Exception e) {
                onHttpError(HttpRequestResult.FAIL_UNKNOWN, HTTP_ENTITY_INVALID);
            }
        } while (false);

        if (mCancel) {
            mCancel = false;
            onCancel();
        }
    }

    public interface HttpCallback {
        void onPrepared();
        void onCompleted(int ret, ResponseBody responseBody);
    }

    private void onHttpPrepare() {
        if (mHttpCallback != null)
            mHttpCallback.onPrepared();
    }

    private void onHttpError(int error, int cause) {
        final HttpCallback callback = mHttpCallback;
        if (callback != null) {
            callback.onCompleted(error, null);
        }
    }

    private void onHttpSuccess(ResponseBody responseBody) {
        final HttpCallback callback = mHttpCallback;
        if (callback != null) {
            callback.onCompleted(HttpRequestResult.SUCCESS, responseBody);
        }
    }

    private void onCancel() {
        final HttpCallback callback = mHttpCallback;
        if (callback != null) {
            callback.onCompleted(HttpRequestResult.CANCEL, null);
        }
    }

    public void cancel() {
        if (!isAlive())
            return;
        mCancel = true;
        if (mCall != null && !mCall.isCanceled())
            mCall.cancel();
        try {
            interrupt();
            join();
        } catch (InterruptedException e) {

        }
    }


    HttpCallback mHttpCallback;

    public void setHttpCallback(HttpCallback callback) {
        this.mHttpCallback = callback;
    }

    private static void supportHttps(OkHttpClient client) {
        try {
            TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };

            SSLContext e = SSLContext.getInstance("TLS");
            e.init(null, new TrustManager[]{tm}, null);
            client.setSslSocketFactory(e.getSocketFactory());

        } catch (Exception e) {
            throw new RuntimeException("supportHttps failed", e);
        }
    }
}
